package proj1.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.ItemSelectable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;

import proj1.constants.C.COMPARATOR;
import proj1.dao.Make;
import proj1.dao.Model;
import proj1.dao.Radiator;
import proj1.dao.Radiator.SIZE;
import proj1.dao.Vendor;
import proj1.ui.component.RadiatorTableModel;
import proj1.util.Logger;

public class RadiatorSearch extends JPanel{
	private static final long serialVersionUID = 1L;
	private static Logger log = Logger.getLogger(RadiatorSearch.class);
	final JTable resultsTable;
	final RadiatorTableModel tableModel;
	final ApplicationFrame mainFrame;
	String[] headers;
	String[] selectedRow = {"", "", "", "", ""};
	final JButton delRad;
	final JButton addRad; 
	final JButton editRad;
	
	public RadiatorSearch(final ApplicationFrame mainFrame){
		addRad = new JButton("Add Radiator");
		addRad.setEnabled(false);
		delRad = new JButton("Delete Radiator");
		delRad.setEnabled(false);
		editRad = new JButton("Edit Radiator");
		editRad.setEnabled(false); 
		
		this.mainFrame = mainFrame;
		headers = new String[] {"Vendor", "Size", "Part Number", "Price", "In Stock"};
		
		// Should not be able to edit values here
		this.tableModel = new RadiatorTableModel();
		this.resultsTable = new JTable(tableModel);

		this.resultsTable.addMouseListener(new MouseAdapter() {
				int click1;
				int row;
				Radiator selectedRadiator;
			
				
				public void mousePressed(MouseEvent e) {
					//if first click, saves the row number of clicked
					if (e.getClickCount()%2==1){ 
						JTable target = (JTable)e.getSource();
						click1 = target.getSelectedRow();
						// Save the data for update and delete functions
						selectedRow[0] = (String) tableModel.getValueAt(click1, 0); //Vendor
						selectedRow[1] = (String) tableModel.getValueAt(click1, 1); //Size
						selectedRow[2] = (String) tableModel.getValueAt(click1, 2); //Part Number
						selectedRow[3] = (String) tableModel.getValueAt(click1, 3); //Price
						selectedRow[4] = (String) tableModel.getValueAt(click1, 4); //InStock
						delRad.setEnabled(true);
						editRad.setEnabled(true);
					}
					//if second click, checks to make sure its the same row thats clicked
					if (e.getClickCount()%2 == 0) {
						JTable target = (JTable)e.getSource();
						row = target.getSelectedRow();
						if (row == click1){
							Vendor vendor = null;
							SIZE size = null;
							String partNum = (String) tableModel.getValueAt(row, 2);
							//gets the vendor of double clicked row
							for(Vendor ven : Vendor.getVendors()){
								if(ven.name().equals(tableModel.getValueAt(row, 1))){
									vendor = ven;
								}
							}
							//gets size of double clicked row
							for(SIZE s : SIZE.values()){
								if(s.toString().equals(tableModel.getValueAt(row, 0))){
									size = s;
								}
							}
							if(vendor!=null && size!=null){
								//gets radiators of selected vendor and size
								//then finds radiator with corresponding partnum
								Set<Radiator> radiators = vendor.getRadiators(size);
								for(Radiator rad : radiators){
									if (rad.getPartNumber().equals(partNum))
										selectedRadiator=rad;
								}
								if(selectedRadiator !=null)
									mainFrame.setContentPane(new RadiatorDescription(mainFrame, selectedRadiator));
							}
						}
					}
				}
		});		
	    
	    resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
		JScrollPane jsp = new JScrollPane(resultsTable);
		Dimension d = new Dimension((int) jsp.getPreferredSize().getWidth(), (resultsTable.getRowHeight()+1)*11);
		jsp.setPreferredSize(d);
		
		
		JPanel subPanel = new JPanel();
		subPanel.setLayout(new GridLayout(1,3));
		subPanel.add(addRad);
		subPanel.add(delRad);
		subPanel.add(editRad);
		setPreferredSize(mainFrame.getPanelSize());
		setLayout(new BorderLayout());
		add(new FilterPanel(), BorderLayout.NORTH);
		add(jsp, BorderLayout.CENTER);
		add(subPanel, BorderLayout.SOUTH);
		setVisible(true);
		
		
	}
	
	// PUT FILTERS HERE 
	private class FilterPanel extends JTabbedPane {
		private static final long serialVersionUID = 1L;
				
		// Make/Model Filters
		private final JComboBox <Make> makeBox;
		private final JComboBox <String> modelBox;
		private final JComboBox <Integer> yearBox;
		private final JComboBox <Model> trimBox;
		
		// Vendor Filters
		private final JComboBox <Vendor> vendorBox;
		private final JComboBox <SIZE> sizeBox;
		
		public FilterPanel(){	
			super();
			
			/* FILTER LABELS */
			JLabel makeLabel = new JLabel("Make");
			JLabel modelLabel = new JLabel("Model");
			JLabel yearLabel = new JLabel("Year");
			JLabel trimLabel = new JLabel("Trim");
			JLabel vendorLabel = new JLabel("Vendor");
			JLabel sizeLabel = new JLabel("Size");
			
			// Make/Model filter init
			makeBox = new JComboBox<>();
			modelBox = new JComboBox<>();
			yearBox = new JComboBox<>();
			trimBox = new JComboBox<>();
			vendorBox = new JComboBox<>();
			sizeBox = new JComboBox<>();
			
			// Disable all but make by default
			makeBox.setEnabled(true);
			modelBox.setEnabled(false);
			yearBox.setEnabled(false);
			trimBox.setEnabled(false);
			sizeBox.setEnabled(false);

			
			/* 				LAYOUT 					*/		
			// Make filter panel
			JPanel makeModelPanel = new JPanel(new GridLayout(2,4));
			makeModelPanel.add(makeLabel); 
			makeModelPanel.add(modelLabel);
			makeModelPanel.add(yearLabel);
			makeModelPanel.add(trimLabel);
			
			makeModelPanel.add(makeBox);			
			makeModelPanel.add(modelBox);
			makeModelPanel.add(yearBox);
			makeModelPanel.add(trimBox);
			
			JPanel vendorPanel = new JPanel(new GridLayout(2,4));
			vendorPanel.add(vendorLabel);
			vendorPanel.add(sizeLabel);
			vendorPanel.add(new JLabel());
			
			vendorPanel.add(vendorBox);
			vendorPanel.add(sizeBox);
			vendorPanel.add(new JLabel());
			
			// Search button et al 
			JPanel actionPanel = new JPanel();
			actionPanel.setAlignmentX(LEFT_ALIGNMENT);
			actionPanel.setAlignmentY(BOTTOM_ALIGNMENT);
			
			for(Make make : Make.getAllMakes())
				makeBox.addItem(make);
			
			for(Vendor vendor : Vendor.values())
				vendorBox.addItem(vendor);
			
			for(SIZE size : SIZE.values())
				sizeBox.addItem(size);
			
			vendorBox.setSelectedIndex(-1);
			sizeBox.setSelectedIndex(-1);
			// Search button
			ItemListener listener = new MakeListener();
			makeBox.addItemListener(listener);
			vendorBox.addItemListener(listener);
			
			addRad.addActionListener(new ActionListener(){
				
				public void actionPerformed(ActionEvent arg0) {
					//either selectedModel will be null or selectedVendor and selectedSize will be null
					mainFrame.setContentPane(new AddNewRadiator(mainFrame, (Model) trimBox.getSelectedItem(), (Vendor) vendorBox.getSelectedItem(), (SIZE)sizeBox.getSelectedItem()));
					
				}
			});
			
			delRad.addActionListener(new ActionListener(){
				
				public void actionPerformed(ActionEvent arg0) {
					mainFrame.setMessage("Radiator Has Been Deleted");
					Radiator selectedRadiator = null;
					Vendor vendor = null;
					SIZE size = null;
					String partNum = selectedRow[2];
					Model model = null;
					for(Vendor ven : Vendor.getVendors()){
						if(ven.name().equals(selectedRow[1])){
							vendor = ven;
						}
					}
					for(SIZE s : SIZE.values()){
						if(s.toString().equals(selectedRow[0])){
							size = s;
						}
					}
					String str = (String) modelBox.getSelectedItem();
					for(Model m : Model.getModels((Make) makeBox.getSelectedItem())){
						if(m.toString().equals(str)){
							model = m;
						}
					}
					if(vendor!=null && size!=null){
						//gets radiators of selected vendor and size
						//then finds radiator with corresponding partnum
						Set<Radiator> radiators = vendor.getRadiators(size);
						for(Radiator rad : radiators){
							if (rad.getPartNumber().equals(partNum))
								selectedRadiator=rad;
						}
						boolean passed = false;
						if(selectedRadiator !=null){
							passed = selectedRadiator.delete( (Model) trimBox.getSelectedItem(), size, vendor);
							int selectedTrim = trimBox.getSelectedIndex();
							trimBox.setSelectedIndex(-1);
							trimBox.setSelectedIndex(selectedTrim);
						}
						log.info("Attempted Deletion of " + trimBox.getSelectedItem() + ", " + size + ", " + vendor + " returned " + passed);
					}
					
				}
			});
			
			editRad.addActionListener(new ActionListener(){
				
				public void actionPerformed(ActionEvent arg0) {
				 
					Radiator selectedRadiator = null;
					Vendor vendor = null;
					SIZE size = null;
					String partNum = selectedRow[2];
					Model model = null;
					for(Vendor ven : Vendor.getVendors()){
						if(ven.name().equals(selectedRow[1])){
							vendor = ven;
						}
					}
					for(SIZE s : SIZE.values()){
						if(s.toString().equals(selectedRow[0])){
							size = s;
						}
					}
					String str = (String) modelBox.getSelectedItem();
					for(Model m : Model.getModels((Make) makeBox.getSelectedItem())){
						if(m.toString().equals(str)){
							model = m;
						}
					}
					if(vendor!=null && size!=null){
						//gets radiators of selected vendor and size
						//then finds radiator with corresponding partnum
						Set<Radiator> radiators = vendor.getRadiators(size);
						for(Radiator rad : radiators){
							if (rad.getPartNumber().equals(partNum))
								selectedRadiator=rad;
						}
						mainFrame.setContentPane(new EditRadiator(mainFrame, (Model) trimBox.getSelectedItem(), size, vendor, selectedRadiator));
					}
						
				}
			});
			// Add to filter
			addTab("Make/Model", makeModelPanel);
			addTab("Vendor", vendorPanel);
			setVisible(true);
		}
		
		@Override
		public Dimension getPreferredSize(){
			Dimension s = super.getPreferredSize();
			s.height = 80;
			return s;
		}
		
		private class MakeListener implements ItemListener {
			// ModelName -> ModelYear -> Set of Models
			Map<String,Map<Integer,Set<Model>>> modelsFilter = new TreeMap<>();
			Map<String, Radiator> radiatorFilter = new TreeMap<>();
			Set <Radiator> radsFromVend;
			Make selectedMake;
			String selectedModelName;
			Integer selectedYear;
			Model selectedModel;
			Vendor selectedVendor;
			SIZE selectedSize;
			
			@Override
			public void itemStateChanged(ItemEvent e) {
				// But this time every time an action is done, the results in the table should update as well
				ItemSelectable is = e.getItemSelectable();
				log.info("ACTION: " + (e.getStateChange() == ItemEvent.SELECTED ? "SELECTED" : "DESELECTED") + " BOX: " + is.toString());
				if(e.getStateChange() == ItemEvent.SELECTED){
					//Make Tab
					if(is.equals(makeBox)){
						log.info("In make");
				
						// Clear selections from model, trim, and year
						modelBox.removeItemListener(this);
						yearBox.removeItemListener(this);
						trimBox.removeItemListener(this);
						
						modelBox.removeAllItems();
						yearBox.removeAllItems();
						trimBox.removeAllItems();
						vendorBox.setSelectedIndex(-1);
						sizeBox.setSelectedIndex(-1);
						// Disable all others
						modelBox.setEnabled(false);
						yearBox.setEnabled(false);
						trimBox.setEnabled(false);
						sizeBox.setEnabled(false);
						addRad.setEnabled(false);
						
						
						// Clear out variables
						selectedModelName = null;
						selectedYear = null;
						selectedModel = null;
						selectedVendor = null;
						selectedSize = null;
						selectedMake = (Make) makeBox.getSelectedItem();
						tableModel.clearTable();
						
						// Initialize the models collection
						modelsFilter.clear();
						
						// Sort the models by name and then by year
						Set<Model> allModels = selectedMake.getModels();
						log.info("Make:" + selectedMake + ". Models Found: " + allModels.size());
						
						// If no models exist for this make, add error message. 
						if(allModels.isEmpty()){
							mainFrame.setErrorMessage("No models found for selected Make");
							return;
						}
							
						// Populate the modelsFilter collection with all of the avaialble models for this make. 
						for(Model model : allModels){
							String modelName = model.getModel();
							Integer modelYear = model.getYear();
							
							Map<Integer,Set<Model>> thisModelYear = modelsFilter.get(modelName);
							
							// If no key exists for this model name, create it
							if(thisModelYear == null)
								modelsFilter.put(modelName, thisModelYear = new TreeMap<>());
							
							// Add this model to the model year set. If it doesn't exist, initialize it
							Set<Model> similarModels = thisModelYear.get(modelYear);
							if(similarModels == null)
								thisModelYear.put(modelYear, similarModels = new TreeSet<>(COMPARATOR.MODEL));
							
							// Finally, put this model into the set
							similarModels.add(model);
						}
						
						// Finally, build the Model select box using the keys from modelsFilter
						for(String modelName : modelsFilter.keySet())
							modelBox.addItem(modelName);
						
						modelBox.setEnabled(true);
						modelBox.addItemListener(this);
						modelBox.setSelectedIndex(-1);
					}
					else if (is.equals(modelBox))
					{
						log.info("In 'model'");
						// Clear selections from year and trim
						yearBox.removeItemListener(this);
						trimBox.removeItemListener(this);
						
						yearBox.removeAllItems();
						trimBox.removeAllItems();
						
						
						yearBox.setEnabled(false);
						trimBox.setEnabled(false);
						addRad.setEnabled(false);
						
						// Clear out variables
						selectedYear = null;
						selectedModel = null;
						tableModel.clearTable();
						
						// Now update the year box to contain all keys found from the
						// modelsFilter map for the selected model name
						selectedModelName = (String) modelBox.getSelectedItem();
						
						Set<Integer> yearsForModel = modelsFilter.get(selectedModelName).keySet();
						log.info("Make: " + selectedMake + " Model Name: " + selectedModelName + " # Year Produced: " + yearsForModel.size());
						
						for(Integer year : yearsForModel)
							yearBox.addItem(year);
	
						yearBox.setEnabled(true);
						yearBox.addItemListener(this);
						yearBox.setSelectedIndex(-1);
					}
					else if (is.equals(yearBox))
					{
						log.info("In 'year'");
						trimBox.removeItemListener(this);
						trimBox.removeAllItems();
						trimBox.setEnabled(false);
						addRad.setEnabled(false);
						// Clear out variables
						selectedModel = null;
						
						tableModel.clearTable();
						
						// Now update the year box to contain all keys found from the
						// modelsFilter map for the selected model year
						selectedYear = (Integer) yearBox.getSelectedItem();
						
						// Get all models from the collection containing this model year
						Set<Model> modelsForYear = modelsFilter.get(selectedModelName).get(selectedYear);
						log.info("Make: " + selectedMake + " Model Name: " + selectedModelName + " Year: " + selectedYear + " Trims Available: " + modelsForYear.size());
						
						for(Model model: modelsForYear)
							trimBox.addItem(model);
						
						trimBox.addItemListener(this); //Nod adding to trimBox for some reason
						trimBox.setEnabled(true);
						trimBox.setSelectedIndex(-1);
						
						ItemListener[] l = trimBox.getItemListeners();
						log.info("Action listeners: " + l.length);
					}
					else if (is.equals(trimBox))
					{
						
						selectedModel = (Model) trimBox.getSelectedItem();
						log.info("In 'trim'.");
						Map<SIZE,Map<Vendor,Set<Radiator>>> radsForTrim = new HashMap<>();
						for(SIZE size : SIZE.values())
							radsForTrim.put(size, selectedModel.getRadiators(size));
						addRad.setEnabled(true);
						tableModel.updateTable(radsForTrim);
					}
					else if (is.equals(vendorBox))
					{
						log.info("In 'vendor'");
						
						
						
						//clear itemActionlisteners
						modelBox.removeItemListener(this);
						yearBox.removeItemListener(this);
						trimBox.removeItemListener(this);
						
						modelBox.removeAllItems();
						yearBox.removeAllItems();
						trimBox.removeAllItems();
						
						
						
						//disable All ComboBoxes
						sizeBox.setEnabled(false);
						modelBox.setEnabled(false);
						yearBox.setEnabled(false);
						trimBox.setEnabled(false);
						addRad.setEnabled(false);
						tableModel.clearTable();
						
						//clear out variables
						selectedModel=null;
						selectedSize=null;
						selectedVendor = (Vendor) vendorBox.getSelectedItem();
						radsFromVend = selectedVendor.getRadiators(); 
						sizeBox.setEnabled(true);
						sizeBox.addItemListener(this);
					}
					else if (is.equals(sizeBox))
					{
						log.info("In 'size'");
						
						
						selectedSize = (SIZE) sizeBox.getSelectedItem();
						
						Map<Vendor,Set<Radiator>> rads = new HashMap<>();
						rads.put(selectedVendor,radsFromVend);
						Map<SIZE,Map<Vendor,Set<Radiator>>> radsForVend = new HashMap<>();
						radsForVend.put(selectedSize, rads);
						tableModel.updateTable(radsForVend);
						addRad.setEnabled(true);
					}
					
					else {
						log.error("INVALID ACTION COMMAND");
					}
				}
			

			
			}
			}

	}
	
	@Override
	public String toString(){
		return "Search Radiators";
	}
}